#pragma once

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/time.h>
#include <atomic>

namespace ns_log
{
    class TimeUtil
    {
    public:
        static std::string GetTimeStamp()
        {
            // 获取时间戳
            struct timeval tv;
            gettimeofday(&tv, nullptr);
            return std::to_string(tv.tv_sec);
        }
        // 获取毫秒级时间戳
        static std::string GetTimeMs()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);
            return std::to_string(tv.tv_sec * 1000 + tv.tv_usec / 1000);
        }
    };

    // 日志等级
    enum
    {
        INFO,    // 正常
        DEBUG,   // 测试
        WARNING, // 警告但不影响运行
        ERROR,   // 当前机器发生错误
        FATAL    // 整个系统崩溃
    };

    // LOG(level) << "message" << "\n";
    inline std::ostream &Log(const std::string &level, const std::string &file_name, int line)
    {
        // 添加日志等级
        std::string message = "[";
        message += level;
        message += "]";

        // 添加报错文件名称
        message += "[";
        message += file_name;
        message += "]";

        // 添加报错行
        message += "[";
        message += std::to_string(line);
        message += "]";

        // 获取时间戳
        message += "[";
        message += TimeUtil::GetTimeStamp();
        message += "]";

        // cout 内部也是有缓冲区的，现将拼接好的message写入cout
        std::cout << message; // 切记！！！不要使用endl进行刷新
        return std::cout;
    }
// 未来在调用日志时，一直传递三个参数太麻烦
// 所以进行宏替换，实现开放式的日志
// 日志等级本质上是整数，在前面添加#可以转为字符串形式
// __FILE__ 和 __LINE__ 可以直接获取当前源文件名以及当前程序的行号
#define LOG(level) Log(#level, __FILE__, __LINE__)
}
